package MobileMWClient;

import jssc.*;

/**
 * <pre>
 * @Package : MobileMWClient
 * @File    : SerialPortReader.java
 * <pre>
 *
 * @Author  : 차재우
 * @Date    : 2013. 7. 26.
 * @Version :
 */
class SerialPortReader implements SerialPortEventListener {
	// 시리얼 포트
	private SerialPort sp = null;
	
	// 시리얼 수신 큐
	private SerialQueue recvQueue = null;
	
	// 버퍼
	private byte[] recvBuf = null;

	// 플래그
	private boolean stxFlag = false;
	private boolean sizeFlag = false;
	private boolean keyFlag = false;
	private boolean dataFlag = false;
	private boolean etxFlag = false;

	// 수신한 데이터 사이즈
	private int dataSize = 0;
	
	// 버퍼 사이즈
	private int recvBufSize = 0;
	
	// 버퍼 인덱스
	private int bufIdx = 0;
	
	/**
	 * <pre>
	 * @Comment : 생성자
	 * <pre>
	 *
	 * @param sp
	 * @param recvQueue
	 */
	public SerialPortReader(SerialPort sp, SerialQueue recvQueue) {
		this.sp = sp;
		this.recvQueue = recvQueue;
	}
	
	private void InitData() {
		stxFlag = sizeFlag = keyFlag = dataFlag = etxFlag = false;
		this.dataSize = this.recvBufSize = this.bufIdx = 0;
	}
	
	/**
	 * <pre>
	 * @Comment : RS232 수신 이벤트
	 * <pre>
	 *
	 * @Method  : serialEvent
	 * @Return  : void 
	 * @param event
	 */
	public void serialEvent(SerialPortEvent event) {
		if (event.isRXCHAR()) {			
			if(stxFlag == false) {
				FindSTX(event);
				return;
			} else if(sizeFlag == false) {
				GetDataSize(event);
				return;
			} else if(keyFlag == false) {
				GetClientKey(event);
				return;
			} else if(dataFlag == false) {
				GetData(event);
				return;
			} else if(etxFlag == false) {
				if(event.getEventValue() < 2)
					return;
				
				FindETX(event);
				InitData();
				return;
			}
		} else if (event.isCTS()) {
			if (event.getEventValue() == 1) {
				System.out.println("CTS - ON");
			} else {
				System.out.println("CTS - OFF");
			}
		} else if (event.isDSR()) {
			if (event.getEventValue() == 1) {
				System.out.println("DSR - ON");
			} else {
				System.out.println("DSR - OFF");
			}
		}
	}
	
	/**
	 * <pre>
	 * @Comment : ETX 필드를 찾는다.
	 * <pre>
	 *
	 * @Method  : FindETX
	 * @Return  : 
	 * @param event
	 */
	private void FindETX(SerialPortEvent event) {
		byte[] etx = null;

		try {
			etx = sp.readBytes(2);
		} catch (SerialPortException ex) {
			ex.printStackTrace();
			return;
		}
		
		if(etx[0] != 0x02 || etx[1] != 0x02)
			return;
		
		etxFlag = true;
		System.out.println("etx find....ok : " + ByteUtil.toHexString(etx));

		// ETX 저장
		try {
			System.arraycopy(etx, 0, recvBuf, bufIdx, etx.length);
			this.recvQueue.Push(recvBuf);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * <pre>
	 * @Comment : 시리얼 데이터 수신
	 * <pre>
	 *
	 * @Method  : RecvData
	 * @Return  : 
	 * @param event
	 */
	private void GetData(SerialPortEvent event) {
		if (event.getEventValue() < dataSize)
			return;
		
		byte[] data = null;

		try {
			data = sp.readBytes(dataSize);
			dataFlag = true;
			System.out.println("data find....ok : " + ByteUtil.toHexString(data));
		} catch (SerialPortException ex) {
			ex.printStackTrace();
			return;
		}

		// DATA 저장
		try {
			System.arraycopy(data, 0, recvBuf, bufIdx, data.length);
			this.bufIdx += data.length;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * <pre>
	 * @Comment : 클라이언트 키 값
	 * <pre>
	 *
	 * @Method  : GetClientKey
	 * @param event
	 */
	private void GetClientKey(SerialPortEvent event) {
		if (event.getEventValue() < 4)
			return;

		byte[] key = null;

		try {
			key = sp.readBytes(4);
			keyFlag = true;
			System.out.println("key find....ok : " + ByteUtil.toHexString(key));
		} catch (SerialPortException ex) {
			ex.printStackTrace();
			return;
		}

		// KEY 저장
		try {
			System.arraycopy(key, 0, recvBuf, bufIdx, key.length);
			this.bufIdx += key.length;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * <pre>
	 * @Comment : Data 필드 사이즈 정보 
	 * <pre>
	 *
	 * @Method  : GetDataSize
	 * @Return  : 
	 * @param event
	 */
	private void GetDataSize(SerialPortEvent event) {
		if (event.getEventValue() < 4)
			return;

		byte[] size = null;

		try {
			size = sp.readBytes(4);
			dataSize = ByteUtil.toInt(size);
			sizeFlag = true;
			System.out.println("size find....ok : " + ByteUtil.toHexString(size));
		} catch (SerialPortException ex) {
			ex.printStackTrace();
			return;
		}

		// 수신버퍼 생성
		this.recvBufSize = GetBufSize();
		this.recvBuf = new byte[recvBufSize];

		// STX 저장
		this.recvBuf[0] = 0x01;
		this.recvBuf[1] = 0x01;
		this.bufIdx += 2;

		// SIZE 저장
		try {
			System.arraycopy(size, 0, recvBuf, bufIdx, size.length);
			this.bufIdx += size.length;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * <pre>
	 * @Comment : STX 필드를 찾는다. 
	 * <pre>
	 *
	 * @Method  : FindSTX
	 * @Return  : 
	 * @param event
	 */
	private void FindSTX(SerialPortEvent event)
	{
		if(event.getEventValue() < 2)
			return;

		byte[] stx = null;

		while (true) {
			do {
				try {
					stx = sp.readBytes(1);
				} catch (SerialPortException ex) {
					ex.printStackTrace();
					return;
				}
			} while (stx[0] != 0x01);

			try {
				stx = sp.readBytes(1);
				if (stx[0] == 0x01) {
					stxFlag = true;
					System.out.println("stx find....ok : " + ByteUtil.toHexString(stx));
					break;
				}
			} catch (SerialPortException ex) {
				ex.printStackTrace();
				return;
			}
		}
	}
	
	/**
	 * <pre>
	 * @Comment : 버퍼 사이즈 계산
	 * <pre>
	 *
	 * @Method  : GetBufSize
	 * @return
	 */
	private int GetBufSize() {
		int size = SerialPacket.STX + SerialPacket.SIZE + SerialPacket.KEY + this.dataSize + SerialPacket.ETX;
		return size;
	}
}
